home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / compmrk.com / TPALLOC.ZIP / TPALLOC.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1988-11-04  |  8.1 KB  |  266 lines

  1. {$S-,R-,I-,V-,B-,D-}
  2.  
  3. {*********************************************************}
  4. {*                    TPALLOC.PAS 1.0                    *}
  5. {*                By TurboPower Software                 *}
  6. {*********************************************************}
  7.  
  8. unit TpAlloc;
  9.   {-Routines for allocating/deallocating blocks of memory larger than 64K}
  10.  
  11. interface
  12.  
  13. type
  14.   SegOfs =                   {structure of a pointer}
  15.     record
  16.       Ofst, Segm : Word;
  17.     end;
  18.  
  19.   {----- memory management routines -----}
  20.  
  21. procedure HugeGetMem(var Pt; Bytes : LongInt);
  22.   {-Allocate a block of memory of size Bytes and store pointer to it in
  23.     Pt. Pt is nil if Bytes > MaxAvail}
  24.  
  25. procedure HugeFreeMem(var Pt; Bytes : LongInt);
  26.   {-Deallocate a block of memory of size Bytes pointed to by Pt, a pointer
  27.     variable. Pt is set to nil on Exit. Does nothing if Pt is nil.}
  28.  
  29.   {----- pointer manipulation routines -----}
  30.  
  31. function Linear(P : Pointer) : LongInt;
  32.   {-Converts a pointer to a linear address to allow differences in addresses
  33.     to be calculated. The pointer must be in the range $0:$0 to $FFFF:$000F.}
  34.  
  35. function LinearToPointer(L : LongInt) : Pointer;
  36.   {-Return linear address L as a normalized pointer}
  37.  
  38. function PtrDiff(P1, P2 : Pointer) : LongInt;
  39.   {-Return the number of bytes between P1^ and P2^}
  40.  
  41. function Normalized(P : Pointer) : Pointer;
  42.   {-Return P as a normalized pointer}
  43.   inline(
  44.     $58/                     {pop ax    ;pop offset into AX}
  45.     $5A/                     {pop dx    ;pop segment into DX}
  46.     $89/$C3/                 {mov bx,ax ;BX = Ofs(P^)}
  47.     $B1/$04/                 {mov cl,4  ;CL = 4}
  48.     $D3/$EB/                 {shr bx,cl ;BX = Ofs(P^) div 16}
  49.     $01/$DA/                 {add dx,bx ;add BX to segment}
  50.     $25/$0F/$00);            {and ax,$F ;mask out unwanted bits in offset}
  51.  
  52.   {=============================================================}
  53.  
  54. implementation
  55.  
  56. type
  57.   FreeListRec =              {structure of a free list entry}
  58.     record
  59.       OrgPtr : Pointer;      {pointer to the start of the block}
  60.       EndPtr : Pointer;      {pointer to the end of the block}
  61.     end;
  62.   FreeListRecPtr = ^FreeListRec;
  63.  
  64.   function Linear(P : Pointer) : LongInt;
  65.     {-Converts a pointer to a linear address to allow differences in addresses
  66.       to be calculated. The pointer must be in the range $0:$0 to $FFFF:$000F.}
  67.   begin
  68.     with SegOfs(P) do
  69.       Linear := (LongInt(Segm) shl 4)+LongInt(Ofst);
  70.   end;
  71.  
  72.   function LinearToPointer(L : LongInt) : Pointer;
  73.     {-Return linear address L as a normalized pointer}
  74.   begin
  75.     LinearToPointer := Ptr(Word(L shr 4), Word(L and $0000000F));
  76.   end;
  77.  
  78.   function PtrDiff(P1, P2 : Pointer) : LongInt;
  79.     {-Return the number of bytes between P1^ and P2^}
  80.   begin
  81.     PtrDiff := Abs(Linear(P1)-Linear(P2));
  82.   end;
  83.  
  84.   procedure HugeGetMem(var Pt; Bytes : LongInt);
  85.     {-Allocate a block of memory of size Bytes and store pointer to it in
  86.       Pt. Pt is nil if Bytes > MaxAvail}
  87.   var
  88.     ThisP : Pointer absolute Pt;
  89.     P : FreeListRecPtr;
  90.     Top : Pointer;
  91.     ThisBlock : LongInt;
  92.   begin
  93.     ThisP := nil;
  94.  
  95.     {point to end of free list}
  96.     P := FreePtr;
  97.     if SegOfs(P).Ofst = 0 then
  98.       Inc(SegOfs(P).Segm, $1000);
  99.  
  100.     {point to top of free memory}
  101.     if FreeMin = 0 then
  102.       Top := Ptr(SegOfs(FreePtr).Segm+$1000, 0)
  103.     else
  104.       Top := Ptr(SegOfs(FreePtr).Segm, -FreeMin);
  105.     if Linear(P) < Linear(Top) then
  106.       Top := P;
  107.  
  108.     {check block at HeapPtr^}
  109.     if PtrDiff(Top, HeapPtr) >= Bytes then begin
  110.       {use this block}
  111.       ThisP := HeapPtr;
  112.  
  113.       {adjust HeapPtr}
  114.       HeapPtr := LinearToPointer(Linear(HeapPtr)+Bytes);
  115.     end
  116.     else while SegOfs(P).Ofst <> 0 do begin
  117.       {search the free list for a memory block that is big enough}
  118.       with P^ do begin
  119.         {calculate the size of the block}
  120.         ThisBlock := PtrDiff(EndPtr, OrgPtr);
  121.  
  122.         if ThisBlock > Bytes then begin
  123.           {bigger than we need--shrink the size of the block}
  124.           ThisP := OrgPtr;
  125.           OrgPtr := LinearToPointer(Linear(OrgPtr)+Bytes);
  126.           Exit;
  127.         end
  128.         else if ThisBlock = Bytes then begin
  129.           {exact size--remove the record from the free list}
  130.           ThisP := OrgPtr;
  131.  
  132.           {move the entry at the bottom of the free list up}
  133.           P^ := FreeListRecPtr(FreePtr)^;
  134.  
  135.           {adjust FreePtr}
  136.           with SegOfs(FreePtr) do
  137.             Inc(Ofst, SizeOf(FreeListRec));
  138.  
  139.           Exit;
  140.         end;
  141.       end;
  142.  
  143.       {point to next record on free list}
  144.       Inc(SegOfs(P).Ofst, SizeOf(FreeListRec));
  145.     end;
  146.   end;
  147.  
  148.   procedure HugeFreeMem(var Pt; Bytes : LongInt);
  149.     {-Deallocate a block of memory of size Bytes pointed to by Pt, a pointer
  150.       variable. Pt is set to nil on Exit. Does nothing if Pt is nil.}
  151.   var
  152.     P : Pointer absolute Pt;
  153.     EndP : Pointer;
  154.     FP, SaveFP, NewFreePtr : FreeListRecPtr;
  155.     I : Word;
  156.     Found : Boolean;
  157.   begin
  158.     {exit if P is nil}
  159.     if (P = nil) then
  160.       Exit;
  161.  
  162.     {calculate pointer to end of block}
  163.     EndP := LinearToPointer(Linear(P)+Bytes);
  164.  
  165.     {see if this is just below HeapPtr^}
  166.     if EndP = HeapPtr then
  167.       {just reset HeapPtr}
  168.       HeapPtr := P
  169.     else begin
  170.       {search for a free list entry to combine this block with}
  171.       Found := False;
  172.       FP := FreePtr;
  173.       while (SegOfs(FP).Ofst <> 0) and not Found do begin
  174.         with FP^ do
  175.           {does the end of our block match the start of this one?}
  176.           if OrgPtr = EndP then begin
  177.             OrgPtr := P;
  178.             Found := True;
  179.           end
  180.           {does the start of our block match the end of this one?}
  181.           else if EndPtr = P then begin
  182.             EndPtr := EndP;
  183.             Found := True;
  184.           end;
  185.  
  186.         {point to next record on free list}
  187.         if not Found then
  188.           Inc(SegOfs(FP).Ofst, SizeOf(FreeListRec));
  189.       end;
  190.  
  191.       if Found then begin
  192.         {save pointer into free list and get pointers to search for}
  193.         SaveFP := FP;
  194.         with FP^ do begin
  195.           P := OrgPtr;
  196.           EndP := EndPtr;
  197.         end;
  198.  
  199.         {see if we can combine this block with a second}
  200.         Found := False;
  201.         FP := FreePtr;
  202.         while (SegOfs(FP).Ofst <> 0) and not Found do begin
  203.           with FP^ do
  204.             {does the end of our block match the start of this one?}
  205.             if OrgPtr = EndP then begin
  206.               OrgPtr := P;
  207.               Found := True;
  208.             end
  209.             {does the start of our block match the end of this one?}
  210.             else if EndPtr = P then begin
  211.               EndPtr := EndP;
  212.               Found := True;
  213.             end;
  214.  
  215.           {point to next record on free list}
  216.           if not Found then
  217.             Inc(SegOfs(FP).Ofst, SizeOf(FreeListRec));
  218.         end;
  219.  
  220.         if Found then begin
  221.           {we combined two blocks--get rid of the 1st free list entry we found}
  222.  
  223.           {move the entry at the bottom of the free list up into its place}
  224.           SaveFP^ := FreeListRecPtr(FreePtr)^;
  225.  
  226.           {adjust FreePtr}
  227.           with SegOfs(FreePtr) do
  228.             Inc(Ofst, SizeOf(FreeListRec));
  229.         end;
  230.       end
  231.       else begin
  232.         {can't combine with anything--add an entry to the free list}
  233.  
  234.         {calculate new FreePtr}
  235.         with SegOfs(FreePtr) do
  236.           NewFreePtr := Ptr(Segm, Ofst-SizeOf(FreeListRec));
  237.  
  238.         {make sure the free list isn't full}
  239.         with SegOfs(NewFreePtr) do
  240.           if (Linear(NewFreePtr) < Linear(HeapPtr)) or (Ofst = 0) then begin
  241.             {it's full--let real FreeMem generate a runtime error}
  242.             if Bytes > 65521 then
  243.               I := 65521
  244.             else
  245.               I := Bytes;
  246.             FreeMem(P, I);
  247.             Exit;
  248.           end;
  249.  
  250.         {fill in the new free list entry}
  251.         with NewFreePtr^ do begin
  252.           OrgPtr := P;
  253.           EndPtr := EndP;
  254.         end;
  255.  
  256.         {adjust FreePtr}
  257.         FreePtr := NewFreePtr;
  258.       end;
  259.  
  260.       {set P to nil}
  261.       P := nil;
  262.     end;
  263.   end;
  264.  
  265. end.
  266.